<?php
//todo 避免每次都重新生成路由配置 以后可以考虑缓存

namespace App;

use Laravel\Lumen\Application as BaseApplication;

class Application extends BaseApplication
{
    /**
     * HTTP请求方式
     * @var array
     */
    private $_http_method = [];

    public function __construct($basePath)
    {
        parent::__construct($basePath);
        $this->_http_method = explode(',', env('APP_HTTP_METHOD'));
    }

    /**
     * 自定义多种路由
     * @param $_methods
     * @param $_uri
     * @param $_action
     */
    public function map($_methods, $_uri, $_action)
    {
        foreach ($_methods as $method) {
            $this->addRoute($method, $_uri, $_action);
        }
    }

    /**
     * 获取路由配置
     * @param string $pathApplication
     * @param string $pathModule
     * @return mixed
     * @author 丁圆圆
     */
    public function getRoutesConfig($pathApplication, $pathModule = '')
    {
        $pathApplicationArr = explode('-', $pathApplication);

        $pathAppStr = '';
        foreach ($pathApplicationArr as $key => $value) {
            $value = ucfirst($value);
            $pathAppStr = $pathAppStr . $value;
        }

        $modulePathArr = explode('-', $pathModule);

        $path = '';
        foreach ($modulePathArr as $key => $value) {

            //首字母转换为大写
            $value = ucfirst($value);
            $path = $path . $value;
        }

        $this->configure('router/' .$pathAppStr.'/'. $path);

        return [$pathModule => $this->make('config')->get('router/' . $pathAppStr.'/'. $path)];
    }

    /**
     * 新的路由生成 （功能等价于 initRoutes）
     */
    public function registerRouter()
    {
        if (PHP_SAPI != "cli") {
            $pathInfo = $this->getPathInfo();
            $pathArr = explode('/', $pathInfo);
            //按需加载路由信息配置文件
            if (isset($pathArr[0]) && isset($pathArr[1]) && isset($pathArr[2]) && isset($pathArr[3]) && isset($pathArr[4]) && isset($pathArr[5])) {
                // 配置中查找目标路由
                $routes = $this->searchTargetRoute($pathArr);
                // 获取不同模块的异常处理中间件名称集合
                $routeMiddleware = array_keys($this->routeMiddleware);
                // 生成lumen路由
                $this->generateGroupRoute($routes, $routeMiddleware);
            }
        }
    }


    private function searchTargetRoute($pathArr)
    {
        $moduleRouteList = $this->getRoutesConfig($pathArr[1], $pathArr[2]);
        $applicationName = $pathArr[1];
        $moduleName = $pathArr[2];
        $version = $pathArr[3];
        $controller = $pathArr[4];
        $action = $pathArr[5];

        $routes = [];
        // 在配置中找出具体目标地址路由（所属的模块和版本）
        if (!empty($moduleRouteList[$moduleName][$version][$controller])) {
            //无驼峰
            if (!empty($moduleRouteList[$moduleName][$version][$controller])) {
                if (isset($moduleRouteList[$moduleName][$version][$controller][$action])) {
                    $routes[$applicationName][$moduleName][$version][$controller][$action] = $moduleRouteList[$moduleName][$version][$controller][$action];
                } else {
                    if (in_array($action, $moduleRouteList[$moduleName][$version][$controller])) {
                        $routes[$applicationName][$moduleName][$version][$controller][] = $action;
                    }
                }
            }
        }

        return $routes;
    }


    private function generateGroupRoute($routes, $routeMiddleWares)
    {
        foreach ($routes as $application => $moduleArr) {

            //模块名称大写例如:WechatCx
            $applicationName = implode('', array_map(function ($_item) {
                return ucfirst($_item);
            }, explode('-', $application)));

            foreach ($moduleArr as $module => $versions) {
                //模块名称大写例如:WechatCx
                $moduleName = implode('', array_map(function ($_item) {
                    return ucfirst($_item);
                }, explode('-', $module)));

                if ($versions) {
                    foreach ($versions as $version => $controllers) {

                        $namespace = 'App\Http\\' . $applicationName . '\\' . $moduleName . '\\' . ucfirst(str_replace('.', '_', $version)) . '\\Controllers';

                        //路由分组
                        $group = [
                            'namespace' => $namespace,
                            'middleware' => ['cross']
                        ];
                        //-----------------app实例,路由组,     模块,     模块名称,     版本,     控制器=>方法,   后置中间件数组
                        $this->group($group, function () use ($application, $module, $moduleName, $version, $controllers, $routeMiddleWares) {

                            foreach ($controllers as $controller => $methods) {

                                if (is_array($methods)) {
                                    foreach ($methods as $k => $method) {

                                        $extraArgs = [];
                                        // $method是数组时，数组元素为方法对应的特定中间件名称
                                        if (is_array($method)) {
                                            $extraArgs = $method;
                                            $method = $k;//$k就是方法
                                        }
                                        //例如:/wechat-cx/v1.0/token/get
                                        $url = strtolower('/' . $application . '/' . $module . '/' . $version . '/' . $controller . '/' . $method);

                                        if (false !== strpos($controller, '-')) {
                                            $controller = implode('', array_map(function ($_item) {
                                                return ucfirst($_item);
                                            }, explode('-', $controller)));
                                        }

                                        //如果方法名里带有-,变成大写。 例如:import-new-user => importNewUser
                                        if (false !== strpos($method, '-')) {
                                            $method = lcfirst(join('', array_map(function ($_item) {
                                                return ucfirst($_item);
                                            }, explode('-', $method))));
                                        }

                                        //拼接方法名称,带Action。importNewUser => importNewUserAction
                                        $method .= 'Action';
                                        //例如:TokenController@getAction
                                        $uses = ucfirst($controller . 'Controller@' . $method);
                                        $args = [
                                            'uses' => $uses,
                                            'middleware' => []
                                        ];
                                        //配置
                                        if (!empty($routeMiddleWares) && in_array($moduleName, $routeMiddleWares)) {
                                            $args['middleware'][] = $moduleName;
                                            if (!empty($extraArgs)) {
                                                $args["middleware"] = array_unique(array_merge($args['middleware'], $extraArgs));
                                            }
                                        }

                                        $this->map($this->_http_method, $url, $args);
                                    }
                                }
                            }
                        });
                    }
                }
            }
        }
    }
}





